#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<sys/time.h>

const off_t SEEK_OFFSET = 512;
const off_t BLK_SZ = 4096;
const u_int32_t LEN = (512 * 1024);  // (2GB / 4KB)

char *write_once_1K   = "/home/write_once_1K";
char *write_once_16K  = "/home/write_once_16K";
char *write_once_64K  = "/home/write_once_64K";
char *write_once_256K = "/home/write_once_256K";
char *write_once_1M   = "/home/write_once_1M";
char *write_once_4M   = "/home/write_once_4M";

char *write_many_2G   = "/home/write_many_2G";



const char *write_data = "f";

void write_once_measure(char *test_path){

    int fd, ret;
    struct timeval start, stop;
    long time_cost;

    gettimeofday(&start, NULL);
    fd = open(test_path, O_WRONLY);
    if(fd < 0) {
        printf("file [%s] open error:%s\n", test_path, strerror(errno));
        exit(-1);
    }
    ret = lseek(fd, SEEK_OFFSET, SEEK_SET);
    if(ret < 0) {
        printf("lseek error:%s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }
    ret = write(fd, write_data, sizeof(write_data));
    if(ret != sizeof(write_data)) {
        printf("write file [%s] error:%s\n", test_path, strerror(errno));
        exit(-1);
    }
    close(fd);
    gettimeofday(&stop, NULL);

    time_cost = ((stop.tv_sec - start.tv_sec) * 1000000L + stop.tv_usec) - start.tv_usec;
    printf("%ld\t", time_cost);
}


void write_many_measure(char *path){

    struct timeval start, stop;
    int fd, ret;
    long total_time_cost = 0;

    // 文件大小2GB，每块大小4KB，一共有len个4KB大小的块
    for(int i = 0; i < LEN; i++){

        gettimeofday(&start, NULL);
        fd = open(write_many_2G, O_WRONLY);
        if(fd < 0){
            printf("file [%s] open error:%s\n", write_many_2G, strerror(errno));
            exit(EXIT_FAILURE);
        }
        ret = lseek(fd, BLK_SZ * i + SEEK_OFFSET, SEEK_SET);
        if(ret < 0){
            printf("lseek error:%s\n", strerror(errno));
            exit(EXIT_FAILURE);
        }
        ret = write(fd, write_data, sizeof(write_data));
        if(ret != sizeof(write_data)){
            printf("write error:%s\n", strerror(errno));
            exit(EXIT_FAILURE);
        }
        close(fd);
        gettimeofday(&stop, NULL);
        total_time_cost += ((stop.tv_sec - start.tv_sec) * 1000000L + stop.tv_usec) - start.tv_usec;
        if(i == 0) {
            printf("%ld\t\t", total_time_cost);
        }
    }

    printf("%ld\t\t", total_time_cost);
    printf("%f\n", total_time_cost / (LEN * 1.0));
}



int main(){

    // 1:
    write_once_measure(write_once_1K);
    // 2:
    write_once_measure(write_once_16K);
    // 3:
    write_once_measure(write_once_64K);
    // 4:
    write_once_measure(write_once_256K);
    // 5:
    write_once_measure(write_once_1M);
    // 6：
    write_once_measure(write_once_4M);
    // 7:
    write_many_measure(write_many_2G);
    return 0;
}